package pwd.allen.jfreechart;

import cn.afterturn.easypoi.entity.ImageEntity;
import lombok.extern.slf4j.Slf4j;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.IntervalCategoryItemLabelGenerator;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.*;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.ui.RectangleEdge;
import org.jfree.chart.util.Rotation;
import org.jfree.chart.util.SortOrder;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;

import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 参考API博客 https://blog.csdn.net/dagecao/article/details/86536680
 */
@Slf4j
public class JfreeUtil {

    static {
        //创建主题样式
        StandardChartTheme standardChartTheme = new StandardChartTheme("CN");
        //设置标题字体
        standardChartTheme.setExtraLargeFont(new Font("宋体", Font.BOLD, 20));
        //设置图例的字体
        standardChartTheme.setRegularFont(new Font("宋体", Font.PLAIN, 15));
        //设置轴向的字体
        standardChartTheme.setLargeFont(new Font("宋体", Font.PLAIN, 15));
        //设置主题样式
        ChartFactory.setChartTheme(standardChartTheme);
    }

    /**
     * 生成饼图
     * @param title 标题
     * @param datas 数据集合
     * @param width 宽度
     * @param height 高度
     * @return
     */
    public static ImageEntity pieChart(String title, Map<String, Number> datas, int width, int height) {

        //饼状图的数据集
        DefaultPieDataset pds = new DefaultPieDataset();
        datas.forEach(pds::setValue);

        //图标标题、数据集合、是否显示图例标识、是否显示tooltips、是否支持超链接
        JFreeChart chart = ChartFactory.createPieChart(title, pds, true, false, false);//平面饼状图
//        JFreeChart chart = ChartFactory.createPieChart3D(title, pds, true, false, false);//3D饼状图
        //设置抗锯齿
        chart.setTextAntiAlias(false);

        /** 设置图标 begin **/
        LegendTitle legend = chart.getLegend();
        //设置图标位置，默认底部
        legend.setPosition(RectangleEdge.BOTTOM);
        legend.setSortOrder(SortOrder.DESCENDING);
        /** 设置图标 end **/

        PiePlot plot = (PiePlot) chart.getPlot();
        //是否完整的圆形
        plot.setCircular(false);
        //设置饼图排列顺序，默认Rotation.CLOCKWISE
        plot.setDirection(Rotation.ANTICLOCKWISE);
        //设置起始角度，默认90（90为12点钟方向，0为3点钟方向）
        plot.setStartAngle(90);
        //如果没有数据则显示的描述，默认是空白
        plot.setNoDataMessage("暂无数据");
        //忽略值为null的分类
        plot.setIgnoreNullValues(true);
        //忽略值为0的分类
        plot.setIgnoreZeroValues(true);
        //设置绘图区边框是否可见
        plot.setOutlineVisible(false);
        //前景透明度
        plot.setForegroundAlpha(0.5f);
        //背景透明度
        plot.setBackgroundAlpha(1f);
        //设置饼状图与边框的间隙空间占比，相当于padding，取值0-0.4之间，默认0.08
        plot.setInteriorGap(0.08);
        //画饼与标签之间的间隙（百分比），默认0.025
        plot.setLabelGap(0.025);
        //是否显示标签连接线，默认true
        plot.setLabelLinksVisible(true);
        //设置标签如何显示，默认false，即标签在饼外边
        plot.setSimpleLabels(false);
        //设置标签阴影颜色
        plot.setShadowPaint(new Color(127, 127, 127));
        //设置标签生成器，0为key、1为数值、2为百分比(默认{0})
        plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0}={1}({2})"));
        //自定义绘图工具，替换默认的颜色选择
        plot.setDrawingSupplier(new DefaultDrawingSupplier(
                new Paint[] {
                        new Color(233, 181, 125),
                        new Color(87, 199, 148),
                        new Color(253, 191, 45),
                        new Color(193, 115, 112),
                        new Color(99, 42, 136),
                        new Color(253, 118, 118),
                        new Color(27, 172, 186),
                        new Color(75, 86, 103),
                        new Color(108, 152, 211),
                        new Color(38, 198, 218),
                        new Color(41, 98, 251),
                        new Color(10, 68, 211)
                }
//                DefaultDrawingSupplier.DEFAULT_PAINT_SEQUENCE
                ,
                DefaultDrawingSupplier.DEFAULT_OUTLINE_PAINT_SEQUENCE,
                DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE,
                DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE,
                DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE));

        //如果是3D饼状图，获取的绘图对象是PiePlot3D类型
        if (plot instanceof PiePlot3D) {
            PiePlot3D plot3D = (PiePlot3D) plot;
            //设置饼状图高度占绘图高度的百分比数，默认0.12
            plot3D.setDepthFactor(0.12);
            //是否使用深度颜色渲染立体的边面
            plot3D.setDarkerSides(true);
        }

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            //将chart输出到内存种的字节输出流
            ChartUtils.writeChartAsJPEG(baos, chart, width, height);
            //保存成图片
            baos.writeTo(new FileOutputStream("target/pieChart.jpg"));
            ImageEntity imageEntity = new ImageEntity(baos.toByteArray(), width, height);
            return imageEntity;
        } catch (IOException e) {
            log.error("生成饼状图失败！", e);
        }
        return null;
    }

    /**
     * 生成柱状图
     * @param title 标题
     * @param categoryAxisLabel x轴标题
     * @param valueAxisLabel y轴标题
     * @param datas 数据集合（系列，（分类, 值））
     * @param width 宽度
     * @param height 高度
     * @return
     */
    public static ImageEntity categoryChart(String title, String categoryAxisLabel, String valueAxisLabel, LinkedHashMap<String,LinkedHashMap<String, Number>> datas, int width, int height) {

        //壮壮图的数据集
        DefaultCategoryDataset cds = new DefaultCategoryDataset();
        datas.forEach((k, v) -> {
            v.forEach((k1, v1) -> {
                cds.addValue(v1, k, k1);
            });
        });
        //图标标题、分类标签、值标签、数据集合、方向、是否显示图例标识（即系列）、是否显示tooltips、是否支持超链接
        JFreeChart chart = ChartFactory.createBarChart(title, categoryAxisLabel, valueAxisLabel, cds, PlotOrientation.VERTICAL,true, false, false);
        //设置抗锯齿
        chart.setTextAntiAlias(false);
        CategoryPlot categoryPlot = chart.getCategoryPlot();
        categoryPlot.setNoDataMessage("暂无数据");
        //设置背景颜色和透明度
        categoryPlot.setBackgroundPaint(new Color(251, 255, 146));
        categoryPlot.setBackgroundAlpha(0.2f);

        //分类轴绘图工具
        CategoryAxis domainAxis = categoryPlot.getDomainAxis();
        /*------设置分类轴坐标上的文字-----------*/
        domainAxis.setTickLabelFont(new Font("宋体", Font.PLAIN, 15));
        /*------设置分类轴的标题文字------------*/
        domainAxis.setLabelFont(new Font("宋体", Font.PLAIN, 15));
        //分类轴上的Lable让其向上45度倾斜
        domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);

        //数值轴绘图工具
        NumberAxis numberaxis = (NumberAxis) categoryPlot.getRangeAxis();
        /*------设置数值轴坐标上的文字-----------*/
        numberaxis.setTickLabelFont(new Font("宋体", Font.PLAIN, 15));
        /*------设置数值轴的标题文字------------*/
        numberaxis.setLabelFont(new Font("宋体", Font.PLAIN, 15));

        //自定义柱子条的渲染器
        BarRenderer renderer = new BarRenderer();
        //是否显示项目标签
        renderer.setDefaultItemLabelsVisible(true);
        //设置项目标签的生成器，在柱子上显示项目标签{2}（2为数值，0为系列，1为分类），数值可以通过numberFormat格式化
        renderer.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator());
        //设置不同大类柱子的颜色，没设置的话会默认有不同的颜色
        renderer.setSeriesPaint(0, new Color(151, 204, 204));
        renderer.setSeriesPaint(1, new Color(232, 114, 140));
        //设置柱子之间间隔，间隔占总宽度的百分比，默认0.02
        renderer.setItemMargin(0.25);
        //是否显示阴影
        renderer.setShadowVisible(true);
        //设置绘画为标准，默认是渐变
        renderer.setBarPainter(new StandardBarPainter());

        categoryPlot.setRenderer(renderer);

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ChartUtils.writeChartAsJPEG(baos, chart, width, height);
            baos.writeTo(new FileOutputStream("target/categoryChart.jpg"));
            ImageEntity imageEntity = new ImageEntity(baos.toByteArray(), width, height);
            return imageEntity;
        } catch (IOException e1) {
            log.error("生成柱状图失败！");
        }
        return null;
    }

    /**
     * 生成环形图
     * @param title
     * @param datas
     * @param width
     * @param height
     * @return
     */
    public static ImageEntity ringChart(String title, Map<String, Number> datas, int width, int height) {

        //根据jfree生成一个本地环形图
        DefaultPieDataset pds = new DefaultPieDataset();
        datas.forEach(pds::setValue);
        //图标标题、数据集合、是否显示图例标识、是否显示tooltips、是否支持超链接
        JFreeChart chart = ChartFactory.createRingChart(title, pds, true, false, false);
        //设置抗锯齿
        chart.setTextAntiAlias(false);
        RingPlot plot = (RingPlot) chart.getPlot();
        plot.setNoDataMessage("暂无数据");
        //忽略无值的分类
        plot.setIgnoreNullValues(true);
        //隐藏画布背景颜色
        plot.setBackgroundPaint(null);
        plot.setSimpleLabels(false);
        //设置绘图区边框是否可见
        plot.setOutlineVisible(false);
        //设置标签阴影颜色
        plot.setShadowPaint(null);
        //设置标签生成器(默认{0})，设置图例数据格式
        plot.setLegendLabelGenerator(new StandardPieSectionLabelGenerator("{0},{1} ({2})", NumberFormat.getNumberInstance(),
                new DecimalFormat("0.00%")));
        //设置标签连线是否可见
        plot.setLabelLinksVisible(false);
        //图形半径
        plot.setLabelGap(0.001D);

        //plot.setSimpleLabels(true);
        plot.setLabelShadowPaint(null);
        plot.setLabelOutlinePaint(new Color(0,true));
        plot.setLabelBackgroundPaint(null);
        plot.setLabelPaint(Color.WHITE);
        //设置饼分隔线
        plot.setSeparatorsVisible(false);
        plot.setSeparatorPaint(Color.WHITE);
        plot.setShadowPaint(new Color(253,253,253));
        plot.setSectionDepth(0.38);
        plot.setStartAngle(90);
        plot.setDrawingSupplier(new DefaultDrawingSupplier(
                new Paint[] {
                        new Color(233, 181, 125),
                        new Color(87, 199, 148),
                        new Color(253, 191, 45),
                        new Color(193, 115, 112),
                        new Color(99, 42, 136),
                        new Color(253, 118, 118),
                        new Color(27, 172, 186),
                        new Color(75, 86, 103),
                        new Color(108, 152, 211),
                        new Color(38, 198, 218),
                        new Color(41, 98, 251),
                        new Color(10, 68, 211)
                }
                ,
                DefaultDrawingSupplier.DEFAULT_OUTLINE_PAINT_SEQUENCE,
                DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE,
                DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE,
                DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE));
        //图例样式的设定,图例含有M 和P 方法
        LegendTitle legendTitle = chart.getLegend();//获得图例标题
        legendTitle.setPosition(RectangleEdge.RIGHT);//图例右边显示
        legendTitle.setBorder(0, 0, 0, 0);//设置图例上下左右线
        legendTitle.setPadding(0, 0, 0, 0);
        //标题的距离的设定
        //TextTitle textTitle = chart.getTitle();	//设置标题居左的距离
        //textTitle.setMargin(0, -200, 0, 0);//标题距离上下左右的距离

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ChartUtils.writeChartAsJPEG(baos, chart, width, height);
            baos.writeTo(new FileOutputStream("target/ringChart.jpg"));
            ImageEntity imageEntity = new ImageEntity(baos.toByteArray(), width, height);
        } catch (IOException e1) {
            log.error("生成环形图失败！");
        }
        return null;
    }
}